/****************************************************************************
 * semidrive/chips/e3650/include/irq.h
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/* This file should never be included directly but, rather,
 * only indirectly through nuttx/irq.h
 */

#ifndef __CHIPS_E3650_INCLUDE_IRQ_H
#define __CHIPS_E3650_INCLUDE_IRQ_H

#include <nuttx/config.h>
#include <arch/armv8-r/irq.h>

#define IDLE_STACK_BASE _core0_idle_stack_start
#define NR_IRQS 434U
#define MODE_MASK     (31UL)
#define MODE_USR      (16UL)
#define MODE_SYS      (31UL)
#define I_BIT_MASK    (1UL << 7U)


#ifndef __ASSEMBLY__
#if defined(CONFIG_RT_FRAMEWORK ) && (CONFIG_RT_FRAMEWORK == 1)
bool up_irq_is_enabled(int irq);
void up_init_irq(int irq, int irq_prio);
void up_clear_irq(int irq);
void up_switch_task_context(void *xcp);
void up_affinity_uart(int irq_prio, int cpu);
int  up_trigger_ipicall(unsigned int cpu);
void up_trigger_ipicalls(unsigned int cpu_mask);
void up_ipicall_attach(void *handler);
bool up_irq_is_enabled(int irq);
void up_init_irq(int irq, int irq_prio);
void up_clear_irq(int irq);
uint32_t up_timer_freq(void);
int up_timer_value(clock_t *ticks);
uint32_t up_timer_gettickfreq(void);

noinstrument_function inline_function void up_set_contexthdl(void *const ctxhdl)
{
	CP15_SET(CONTEXTIDR, ctxhdl);
}

noinstrument_function inline_function void *up_get_contexthdl()
{
	return (void *)CP15_GET(CONTEXTIDR);
}

#if defined(CONFIG_RT_FRAMEWORK ) && (CONFIG_RT_FRAMEWORK == 1)
#define SYS_syscall_return       (3)
void syscall_handler(void *syscall_args, uint32_t *regs);
bool is_privilege_mode(void);
void up_syscall(void *syscall_args);

/* called directly */

static inline_function void up_set_privilege_to_user(void)
{
	uintptr_t cpsr;

	__asm volatile("mrs %0, cpsr" : "=r" (cpsr));
	cpsr &= ~MODE_MASK;
	cpsr |= MODE_USR;
	__asm volatile("msr cpsr, %0" : : "r" (cpsr));
}

/*called by trap*/

static inline_function void up_set_int_stack(uint32_t *regs)
{
	if (0U == (regs[REG_CPSR] & I_BIT_MASK)) {
		up_irq_enable();
	}
}

static inline_function void up_restore_int_stack(uint32_t *regs)
{
	if (0U == (regs[REG_CPSR] & I_BIT_MASK)) {
		up_irq_disable();
	}
}

static inline_function void up_set_user_to_privilege(uint32_t *regs)
{
	uintptr_t cpsr;

	cpsr = regs[REG_CPSR];
	cpsr &= ~MODE_MASK;
	cpsr |= MODE_SYS;
	regs[REG_CPSR] = cpsr;
}

static inline_function void up_set_int_from_syscall(uint32_t *regs)
{
	uintptr_t cur_cpsr;
	uintptr_t user_cpsr;

	__asm volatile("mrs %0, cpsr" : "=r" (cur_cpsr));
	cur_cpsr &= I_BIT_MASK;
	user_cpsr = regs[REG_CPSR];
	user_cpsr &= ~I_BIT_MASK;
	user_cpsr |= cur_cpsr;
	regs[REG_CPSR] = user_cpsr;
}

#endif /* CONFIG_RT_FRAMEWORK_SYSCALL */
#endif /* CONFIG_RT_FRAMEWORK */

#endif /* __ASSEMBLY__ */

#endif /* __CHIPS_E3650_INCLUDE_IRQ_H */
